#include "decoder_flac_metadata.h"
#include "debug.h"

// ----------------
void FLACMetadata::init(AudioReader* ar) {
// ----------------
	// <1>  last-meta flag
	// <7>  meta type
	// <24> size (bytes)
	
	reader = ar;
	last = false;
	size = 0;
	dataStart = reader->tell();
	#ifdef DEBUG_DEC_FLAC_META
	iprintf("[FLAC:M] dataStart: %ld\n", dataStart);
	#endif
}

// ----------------
FLACmetatype FLACMetadata::getType() {
// ----------------
	return type;
}

// ----------------
bool FLACMetadata::nextBlock()
// ----------------
{
	reader->seek(dataStart+size);
	dataStart = reader->tell() + 4;
	if (last == true) return false;
	
	uint32_t tmp;
	if (!reader->read_uint32_be(&tmp, 8)) return false;
	last = (tmp >> 7) ? true : false;
	type = FLAC_ERROR;

	switch ( tmp & 0x7F ) {
		case 0: type = FLAC_STREAMINFO;     break;
		case 1: type = FLAC_PADDING;        break;
		case 2: type = FLAC_APPLICATION;    break;
		case 3: type = FLAC_SEEKTABLE;      break;
		case 4: type = FLAC_VORBIS_COMMENT; break;
		case 5: type = FLAC_CUESHEET;       break;
		case 6: type = FLAC_PICTURE;        break;
	}
	
	if (!reader->read_uint32_be(&size, 24)) return false;

	#ifdef DEBUG_DEC_FLAC_META
	iprintf("[FLAC:M] Block: %d, %d, %d\n", last, type, size);
	iprintf("[FLAC:M] Position: %ld\n", reader->tell());
	iprintf("[FLAC:M] dataStart: %ld\n", dataStart);
	scanKeys(); while (!(keysDown() & KEY_Y)) {scanKeys(); swiWaitForVBlank();}	swiWaitForVBlank();
	#endif

	return true;
}

// ----------------
FLACstreaminfo FLACMetadata::readStreaminfo() {
// ----------------
	FLACstreaminfo data;
	uint32_t tmp;
	
	// <16> minimum block size
	reader->read_uint32_be(&tmp, 16);
	data.minblocksize = tmp;
	
	// <16> maximum block size
	reader->read_uint32_be(&tmp, 16);
	data.maxblocksize = tmp;
	
	// <24> minimum frame size
	reader->read_uint32_be(&data.minframesize, 24);
	
	// <24> maximum frame size
	reader->read_uint32_be(&data.maxframesize, 24);
	
	// <20> sample rate
	reader->read_uint32_be(&data.samplerate, 20);
	
	// <3> number of channels (-1)
	reader->read_uint32_be(&tmp, 3);
	data.channels = tmp + 1;

	// <5> bits per sample (-1)
	reader->read_uint32_be(&tmp, 5);
	data.bitspersample = tmp + 1;

	// <36> total samples
	uint64_t tmp64;
	reader->read_uint64_be(&tmp64, 36);
	data.samples = tmp64;

	// <128> md5 checksum
	reader->read_byte_block((uint8_t *)&data.md5, 16, true);
	
	#ifdef DEBUG_DEC_FLAC_META_STREAMINFO
	iprintf("Min block size: %u (%x)\n", data.minblocksize, data.minblocksize);
	iprintf("Max block size: %u (%x)\n", data.maxblocksize, data.maxblocksize);
	iprintf("Min frame size: %u (%x)\n", data.minframesize, data.minframesize);
	iprintf("Max frame size: %u (%x)\n", data.maxframesize, data.maxframesize);
	iprintf("Sample rate: %u (%x)\n", data.samplerate, data.samplerate);
	iprintf("Channels: %u (%x)\n", data.channels, data.channels);
	iprintf("Bits/sample: %u (%x)\n", data.bitspersample, data.bitspersample);
	iprintf("Total samples: %u (%x)\n", data.samples, data.samples);
	iprintf("MD5: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
				data.md5[ 0], data.md5[ 1], data.md5[ 2], data.md5[ 3],
				data.md5[ 4], data.md5[ 5], data.md5[ 6], data.md5[ 7], 
				data.md5[ 8], data.md5[ 9], data.md5[10], data.md5[11], 
				data.md5[12], data.md5[13], data.md5[14], data.md5[15]);
	#endif
  
  return data;
}

// ----------------
std::vector<FLACseekpoint> FLACMetadata::readSeektable() {
// ----------------
	std::vector<FLACseekpoint> table;
	FLACseekpoint point;
	
	uint8_t total = size / 18;
	uint32_t tmp;

	for (uint8_t i=0; i<total; ++i)
	{
		reader->read_uint64_be(&point.samplenumber, 64);
		reader->read_uint64_be(&point.offset, 64);
		reader->read_uint32_be(&tmp, 16);
		point.samples = tmp;
		table.push_back(point);
	}

	#ifdef DEBUG_DEC_FLAC_META_SEEKTABLE
	iprintf("Total seekpoints: %d\n", total);
	for (u8 i=0; i<table.size(); ++i)
	{
		iprintf("#%02d:%u,%u,%u\n", i, (uint32_t)table[i].samplenumber, (uint32_t)table[i].offset, table[i].samples);
	}
	#endif

  return table;
}
    
// ----------------
FLACvorbis FLACMetadata::readVorbisComment()
// ----------------
{
	FLACvorbis vorbis;
	uint32_t length = 0;
	uint8_t  cstring[256];
	uint32_t user_comment_list_length = 0;
	
	/* read vendor string */
	reader->read_uint32_le(&length, 32);
	#ifdef DEBUG_DEC_FLAC_META_VORBIS
	iprintf("vendor_length=%u\n", length);
	#endif
	reader->read_byte_block(cstring, length, true);
	cstring[length] = 0;

	vorbis.vendorString.assign((char *)cstring, length);
	#ifdef DEBUG_DEC_FLAC_META_VORBIS
	iprintf("\nvendor_string=%s\n", vorbis.vendorString.data());
	#endif
	
	/* read fields */
	reader->read_uint32_le(&user_comment_list_length, 32);
	#ifdef DEBUG_DEC_FLAC_META_VORBIS
	iprintf("user_comment_list_length=%u\n", user_comment_list_length);
	#endif

	FLAComment comment;
	size_t delimiter;
	std::string string;

	for (uint32_t i=0; i<user_comment_list_length; ++i)
	{
		// read size
		reader->read_uint32_le(&length, 32);
		// read string
		reader->read_byte_block(cstring, length, true);
		cstring[length] = 0;
		string.assign((char *)cstring, length);
		delimiter = string.find('=');
		comment.name = string.substr(0, delimiter);
		comment.data = string.substr(delimiter+1);
		vorbis.comments.push_back(comment);
		#ifdef DEBUG_DEC_FLAC_META_VORBIS
		iprintf("%s=%s\n", comment.name.data(), comment.data.data());
		#endif
	}

	return vorbis;
}

